AIDL Hal 开发指南 4 ———— AIDL HAL 实例分析2

4/8/2024

light hal 的调用流程与 Vibrator 基本移植,主要区别是 light 直接用 java 和 hal 通信,没有用 jni。接下来我们分析一下 SystemServer 中的 light 硬件服务与 hal 通信的过程。

整体架构如下:

20240408102733

# SystemServer 中的 LightsService

在 SystemServer 的 startBootstrapServices 方法中找到 LightsService 的启动过程:

// frameworks/base/services/java/com/android/server/SystemServer.java
    private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
      //......
        t.traceBegin("StartLightsService");
        mSystemServiceManager.startService(LightsService.class);
        t.traceEnd();     
      //......
    }
1
2
3
4
5
6
7
8

接着看 LightService 的具体实现:

// frameworks/base/services/core/java/com/android/server/lights/LightsService.java
public class LightsService extends SystemService {
    @VisibleForTesting
    final LightsManagerBinderService mManagerService;

    private final class LightsManagerBinderService extends ILightsManager.Stub {
      // ......
    }

    @VisibleForTesting
    LightsService(Context context, Supplier<ILights> service, Looper looper) {
        super(context);
        mH = new Handler(looper);
        mVintfLights = service.get() != null ? service : null;

        populateAvailableLights(context);
        // 初始化一个 binder 服务端对象
        mManagerService = new LightsManagerBinderService();
    }
****
    @Override
    public void onStart() {
        publishLocalService(LightsManager.class, mService);
        // 向 ServiceManager 注册 LightsManagerBinderService
        publishBinderService(Context.LIGHTS_SERVICE, mManagerService);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

LightService 有一个重要成员 LightsManagerBinderService,这是一个 LightsService 中的内部类,是 ILightsManager binder 服务的服务端类实现。

其对应的协议文件 aidl 的实现如下:

// frameworks/base/core/java/android/hardware/lights/ILightsManager.aidl

package android.hardware.lights;

import android.hardware.lights.Light;
import android.hardware.lights.LightState;

/**
 * API to lights manager service.
 *
 * {@hide}
 */
interface ILightsManager {
  List<Light> getLights();
  LightState getLightState(int lightId);
  void openSession(in IBinder sessionToken, in int priority);
  void closeSession(in IBinder sessionToken);
  void setLightStates(in IBinder sessionToken, in int[] lightIds, in LightState[] states);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

LightsManagerBinderService 向 App 提供访问接口,接下的问题 LightsManagerBinderService 如何访问到 Hal 层。

# LightsManagerBinderService 如何访问到 HAL

LightsService 中有一个成员 Supplier<ILights> mVintfLights

// frameworks/base/services/core/java/com/android/server/lights/LightsService.java
public class LightsService extends SystemService {
    @Nullable
    private final Supplier<ILights> mVintfLights;
}
1
2
3
4
5

ILights 是什么? 就是 Hal Binder 服务。

// hardware/interfaces/light/aidl/android/hardware/light/ILights.aidl
package android.hardware.light;

import android.hardware.light.HwLightState;
import android.hardware.light.HwLight;

/**
 * Allows controlling logical lights/indicators, mapped to LEDs in a
 * hardware-specific manner by the HAL implementation.
 */
@VintfStability
interface ILights {
    /**
     * Set light identified by id to the provided state.
     *
     * If control over an invalid light is requested, this method exists with
     * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a
     * device-specific best-effort basis and unsupported sub-features will not
     * be reported.
     *
     * @param id ID of logical light to set as returned by getLights()
     * @param state describes what the light should look like.
     */
    void setLightState(in int id, in HwLightState state);

    /**
     * Discover what lights are supported by the HAL implementation.
     *
     * @return List of available lights
     */
    HwLight[] getLights();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

Hal Binder 服务代理端怎么获取到:

// frameworks/base/services/core/java/com/android/server/lights/LightsService.java

public class LightsService extends SystemService {
    @Nullable
    private final Supplier<ILights> mVintfLights;

    public LightsService(Context context) {
        // new 了一个 VintfHalCache 对象
        this(context, new VintfHalCache(), Looper.myLooper());
    }

    LightsService(Context context, Supplier<ILights> service, Looper looper) {
        super(context);
        mH = new Handler(looper);
        // 调用 get 方法,返回值赋值给成员
        mVintfLights = service.get() != null ? service : null;
        populateAvailableLights(context);
        mManagerService = new LightsManagerBinderService();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

接着看 VintfHalCache 中 get 方法的实现:

// frameworks/base/services/core/java/com/android/server/lights/LightsService.java
    private static class VintfHalCache implements Supplier<ILights>, IBinder.DeathRecipient {
        @GuardedBy("this")
        private ILights mInstance = null;

        @Override
        public synchronized ILights get() {
            if (mInstance == null) {
              // 获取 hal binder 服务
                IBinder binder = Binder.allowBlocking(
                        ServiceManager.waitForDeclaredService(ILights.DESCRIPTOR + "/default"));
                if (binder != null) {
                    mInstance = ILights.Stub.asInterface(binder);
                    try {
                        binder.linkToDeath(this, 0);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Unable to register DeathRecipient for " + mInstance);
                    }
                }
            }
            return mInstance;
        }

        @Override
        public synchronized void binderDied() {
            mInstance = null;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

这里会获取到 hal binder 服务的代理端对象。

# 发起远程调用,调用 hal 层

绝大部分 light 硬件操作,最终都会调用到 setLightUnchecked 方法中

        private void setLightUnchecked(int color, int mode, int onMS, int offMS,
                int brightnessMode) {
            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
                    + Integer.toHexString(color) + ")");
            try {
                if (mVintfLights != null) {
                    HwLightState lightState = new HwLightState();
                    lightState.color = color;
                    lightState.flashMode = (byte) mode;
                    lightState.flashOnMs = onMS;
                    lightState.flashOffMs = offMS;
                    lightState.brightnessMode = (byte) brightnessMode;
                    // 发起远程调用
                    mVintfLights.get().setLightState(mHwLight.id, lightState);
                } else {
                    setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
                }
            } catch (RemoteException | UnsupportedOperationException ex) {
                Slog.e(TAG, "Failed issuing setLightState", ex);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_POWER);
            }
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

可以看出这里是直接通过 java 接口与 hal 通信。

# hal 服务的实现

最后,我们来看看 hal 层的实现:

// hardware/interfaces/light/aidl/default/Lights.h
#pragma once

#include <aidl/android/hardware/light/BnLights.h>

namespace aidl {
namespace android {
namespace hardware {
namespace light {

// Default implementation that reports a few placeholder lights.
class Lights : public BnLights {
    ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
    ndk::ScopedAStatus getLights(std::vector<HwLight>* lights) override;
};

}  // namespace light
}  // namespace hardware
}  // namespace android
}  // namespace aidl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

cpp 中没有具体操作硬件,空实现。需要硬件厂商来做实现。

// hardware/interfaces/light/aidl/default/Lights.cpp
#include "Lights.h"

#include <android-base/logging.h>

namespace aidl {
namespace android {
namespace hardware {
namespace light {

static constexpr int kNumDefaultLights = 3;

ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
    LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color;
    if (id <= 0 || id > kNumDefaultLights) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    } else {
        return ndk::ScopedAStatus::ok();
    }
}

ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* lights) {
    for (int i = 1; i <= kNumDefaultLights; i++) {
        lights->push_back({i, i});
    }
    LOG(INFO) << "Lights reporting supported lights";
    return ndk::ScopedAStatus::ok();
}

}  // namespace light
}  // namespace hardware
}  // namespace android
}  // namespace aidl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34